{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Himmelblau 函数的模拟"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "torch.manual_seed(seed=0) # 固定随机数种子,这样生成的数据是确定的\n",
    "sample_num = 1000 # 生成样本数\n",
    "features = torch.rand(sample_num, 2)  * 12 - 6 # 特征数据\n",
    "noises = torch.randn(sample_num)\n",
    "def himmelblau(x):\n",
    "    return (x[:,0] ** 2 + x[:,1] - 11) ** 2 + (x[:,0] + x[:,1] ** 2 - 7) ** 2\n",
    "hims = himmelblau(features) * 0.01\n",
    "labels = hims + noises # 标签数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "真实:训练集MSE = 0.918333, 验证集MSE = 0.902182, 测试集MSE = 0.978382\n"
     ]
    }
   ],
   "source": [
    "train_num, validate_num, test_num = 600, 200, 200 # 分割数据\n",
    "train_mse = torch.mean(noises[:train_num] ** 2)\n",
    "validate_mse = torch.mean(noises[train_num:-test_num] ** 2)\n",
    "test_mse = torch.mean(noises[-test_num:] ** 2)\n",
    "print ('真实:训练集MSE = {:g}, 验证集MSE = {:g}, 测试集MSE = {:g}'.format(\n",
    "        train_mse, validate_mse, test_mse))\n",
    "# 输出: 真实:训练集MSE = 0.918333, 验证集MSE = 0.902182, 测试集MSE = 0.978382"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "搭建神经网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "神经网络为 Sequential(\n",
      "  (0): Linear(in_features=2, out_features=6, bias=True)\n",
      "  (1): Sigmoid()\n",
      "  (2): Linear(in_features=6, out_features=2, bias=True)\n",
      "  (3): Sigmoid()\n",
      "  (4): Linear(in_features=2, out_features=1, bias=True)\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "hidden_features = [6, 2] # 指定隐含层数\n",
    "layers = [nn.Linear(2, hidden_features[0]),]\n",
    "for idx, hidden_feature in enumerate(hidden_features):\n",
    "    layers.append(nn.Sigmoid())\n",
    "    next_hidden_feature = hidden_features[idx + 1] \\\n",
    "            if idx + 1 < len(hidden_features) else 1\n",
    "    layers.append(nn.Linear(hidden_feature, next_hidden_feature))\n",
    "net = nn.Sequential(*layers) # 前馈神经网络\n",
    "print('神经网络为 {}'.format(net))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "训练网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#0 训练集MSE = 21.2744, 验证集MSE = 24.1956\n",
      "#10000 训练集MSE = 1.95013, 验证集MSE = 1.92581\n",
      "#20000 训练集MSE = 1.09843, 验证集MSE = 1.20965\n",
      "#30000 训练集MSE = 1.07242, 验证集MSE = 1.19141\n",
      "#40000 训练集MSE = 1.06652, 验证集MSE = 1.18404\n",
      "#50000 训练集MSE = 1.05888, 验证集MSE = 1.17478\n",
      "#60000 训练集MSE = 1.05366, 验证集MSE = 1.15356\n",
      "#70000 训练集MSE = 1.05081, 验证集MSE = 1.13395\n",
      "#80000 训练集MSE = 1.04794, 验证集MSE = 1.10615\n",
      "#90000 训练集MSE = 1.04472, 验证集MSE = 1.07885\n",
      "训练集MSE = 1.04095, 验证集MSE = 1.06708\n"
     ]
    }
   ],
   "source": [
    "optimizer = torch.optim.Adam(net.parameters())\n",
    "criterion = nn.MSELoss()\n",
    "\n",
    "train_entry_num = 600 # 选择训练样本数\n",
    "    \n",
    "nIteration = 100000 # 00 # 最大迭代次数\n",
    "for step in range(nIteration):\n",
    "    outputs = net(features)\n",
    "    preds = outputs[:, 0]\n",
    "    \n",
    "    loss_train = criterion(preds[:train_entry_num],\n",
    "            labels[:train_entry_num])\n",
    "    loss_validate = criterion(preds[train_num:-test_num],\n",
    "            labels[train_num:-test_num])\n",
    "    if step % 10000 == 0:\n",
    "        print ('#{} 训练集MSE = {:g}, 验证集MSE = {:g}'.format(\n",
    "                step, loss_train, loss_validate))\n",
    "\n",
    "    optimizer.zero_grad()\n",
    "    loss_train.backward()\n",
    "    optimizer.step()\n",
    "\n",
    "print ('训练集MSE = {:g}, 验证集MSE = {:g}'.format(loss_train, loss_validate))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
